﻿//     Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Diagnostics;
using System.IdentityModel.Tokens;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using Microsoft.Gateway.Utils;
using Microsoft.Web.Administration;

namespace Microsoft.Gateway.RulesConfigurator
{
    class DirectoryConfigurator
    {
        // Module Names - Make sure these names correspond to the values in the deployed web.config
        const string ModuleNameFam = "GatewayFAM";
        const string ModuleNameSam = "SessionAuthenticationModule";

        public static ConfiguratorResults ApplyConfiguration(string domain, string applicationName, string configPath = null)
        {
            try
            {
                if (String.IsNullOrWhiteSpace(configPath) && !AzureUtils.TryGetConfigPath(out configPath))
                {
                    Trace.TraceInformation("DirectoryConfigurator: website not available yet, so not running configuration.");
                    return ConfiguratorResults.RetryLater;
                }
                bool enableAuth = !String.IsNullOrWhiteSpace(domain) && !String.IsNullOrWhiteSpace(applicationName);
                if (enableAuth)
                {
                    ValidatingIssuerNameRegistry.WriteToConfig(AzureEnvironment.FederationMetadataLocation(domain), configPath);
                }
                XDocument config = XDocument.Load(configPath);
                if (enableAuth)
                {
                    // Enabling AuthN
                    var value = XNamespace.None + "value";

                    config.XPathSelectElement("//configuration/appSettings/add[@key = 'ida:FederationMetadataLocation']")
                        .SetAttributeValue(value, AzureEnvironment.FederationMetadataLocation(domain));
                    config.XPathSelectElement("//configuration/appSettings/add[@key = 'ida:Issuer']")
                        .SetAttributeValue(value, AzureEnvironment.WsFedIssuerEndpoint(domain));
                    config.XPathSelectElement("//configuration/system.identityModel/identityConfiguration/audienceUris/add")
                        .SetAttributeValue(value, applicationName);
                    config.XPathSelectElement("//configuration/system.identityModel.services/federationConfiguration/wsFederation")
                        .SetAttributeValue("issuer", AzureEnvironment.WsFedIssuerEndpoint(domain));
                    config.XPathSelectElement("//configuration/system.identityModel.services/federationConfiguration/wsFederation")
                        .SetAttributeValue("realm", applicationName);
                    EnableModule(config, ModuleNameFam, "GatewayFAM.GWFederationAuthenticationModule, GatewayFAM");
                    EnableModule(config, ModuleNameSam, "System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
                }
                else
                {
                    DisableModule(config, ModuleNameFam);
                    DisableModule(config, ModuleNameSam);
                }
               
                config.Save(configPath);
                return ConfiguratorResults.Success;
            }
            catch (Exception ex)
            {
                Trace.TraceError("Failed to update authentication settings for web server. Details: {0}", ex);
            }
            return ConfiguratorResults.Failure;
        }

        static void EnableModule(XDocument config, string moduleName, string moduleTypeName)
        {
            AddOrRemoveModule(config, moduleName, moduleTypeName, true);
        }

        static void DisableModule(XDocument config, string moduleName)
        {
            AddOrRemoveModule(config, moduleName, String.Empty, false);
        }

        static void AddOrRemoveModule(XDocument config, string moduleName, string moduleTypeName, bool enable)
        {
            var currentModule = config.XPathSelectElement(String.Format("//configuration/system.webServer/modules/add[@name = '{0}']", moduleName));
            if (enable && currentModule == null)
            {
                var modules = config.XPathSelectElement("//configuration/system.webServer/modules");
                modules.Add(new XElement(XNamespace.None + "add", 
                    new XAttribute(XNamespace.None + "name", moduleName),
                    new XAttribute(XNamespace.None + "type", moduleTypeName)));
            }
            else if (!enable && currentModule != null)
            {
                currentModule.Remove();
            }
        }
    }
}
